/*
 * Engine interface display, by Tyler Eastman
 *
 */

package chessengine;

import bbchess.MainGui;
import bbchess.units.ChessBoard;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;

/**
 *
 * @author Tyler
 */
public class EngineInterface extends javax.swing.JDialog {

    // initialize variables
    MainGui gui;
    ChessBoard board;
    boolean killEngineReader;
    private Process p;
    private BufferedReader stdInput;
    private BufferedWriter stdOutput;
    private Thread engineReader;
    private String move;
    private boolean isReady;

    /** Creates new form EngineInterface */
    public EngineInterface(java.awt.Frame parent, boolean modal) {
        super(parent, modal);
        initComponents();
        this.setLocationRelativeTo(null);
        inputField.requestFocus();
        gui = (MainGui) getParent();
        board = gui.getChessBoard();
        killEngineReader = false;
        isReady = false;

        engineTextArea.append(startEngine());
    }

    @Override
    public void setVisible(boolean b) {
        // if dialog is set to visible, transfer focus back to inputField
        if (b) {
            if (!inputField.hasFocus()) {
                inputField.requestFocus();
            }
        }
        super.setVisible(b);
    }

    @Override
    public void dispose() {
        MainGui parentFrame = (MainGui) this.getParent();
        parentFrame.setEngineMenuItemSelected(false);
        this.setVisible(false);
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        jPanel1 = new javax.swing.JPanel();
        inputField = new javax.swing.JTextField();
        sendButton = new javax.swing.JButton();
        jScrollPane1 = new javax.swing.JScrollPane();
        engineTextArea = new javax.swing.JTextArea();
        jPanel2 = new javax.swing.JPanel();
        jLabel1 = new javax.swing.JLabel();
        lastMoveLabel = new javax.swing.JLabel();
        jMenuBar1 = new javax.swing.JMenuBar();
        engineMenu = new javax.swing.JMenu();
        jSeparator1 = new javax.swing.JPopupMenu.Separator();
        startEngineMenuItem = new javax.swing.JMenuItem();
        stopEngineMenuItem = new javax.swing.JMenuItem();

        setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
        setTitle("Engine");

        jPanel1.setBorder(javax.swing.BorderFactory.createTitledBorder("Engine"));

        sendButton.setText("Send");
        sendButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                sendButtonActionPerformed(evt);
            }
        });

        jScrollPane1.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
        jScrollPane1.setAutoscrolls(true);

        engineTextArea.setColumns(20);
        engineTextArea.setEditable(false);
        engineTextArea.setRows(5);
        jScrollPane1.setViewportView(engineTextArea);

        javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
        jPanel1.setLayout(jPanel1Layout);
        jPanel1Layout.setHorizontalGroup(
            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup()
                .addComponent(inputField, javax.swing.GroupLayout.DEFAULT_SIZE, 289, Short.MAX_VALUE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(sendButton))
            .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 352, Short.MAX_VALUE)
        );
        jPanel1Layout.setVerticalGroup(
            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup()
                .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 140, Short.MAX_VALUE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(inputField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(sendButton)))
        );

        jPanel2.setBorder(javax.swing.BorderFactory.createTitledBorder("Information"));

        jLabel1.setText("Last Move: ");

        javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2);
        jPanel2.setLayout(jPanel2Layout);
        jPanel2Layout.setHorizontalGroup(
            jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel2Layout.createSequentialGroup()
                .addComponent(jLabel1)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(lastMoveLabel)
                .addContainerGap(290, Short.MAX_VALUE))
        );
        jPanel2Layout.setVerticalGroup(
            jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel2Layout.createSequentialGroup()
                .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel1)
                    .addComponent(lastMoveLabel))
                .addContainerGap(31, Short.MAX_VALUE))
        );

        engineMenu.setText("Engine");
        engineMenu.add(jSeparator1);

        startEngineMenuItem.setText("Start Engine");
        startEngineMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                startEngineMenuItemActionPerformed(evt);
            }
        });
        engineMenu.add(startEngineMenuItem);

        stopEngineMenuItem.setText("Stop Engine");
        stopEngineMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                stopEngineMenuItemActionPerformed(evt);
            }
        });
        engineMenu.add(stopEngineMenuItem);

        jMenuBar1.add(engineMenu);

        setJMenuBar(jMenuBar1);

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(jPanel2, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addComponent(jPanel1, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jPanel2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap())
        );

        pack();
    }// </editor-fold>//GEN-END:initComponents

    private void sendButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_sendButtonActionPerformed
        try {
            String inText = inputField.getText();
            inputField.setText("");
            tellEngine(inText);
        } catch (Exception ex) {engineTextArea.setText("Engine not initialized");}
    }//GEN-LAST:event_sendButtonActionPerformed

    private void startEngineMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_startEngineMenuItemActionPerformed
        engineTextArea.append(startEngine());
    }//GEN-LAST:event_startEngineMenuItemActionPerformed

    private void stopEngineMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_stopEngineMenuItemActionPerformed
        stopEngine();
    }//GEN-LAST:event_stopEngineMenuItemActionPerformed

    public String startEngine() {

        // initialize variables
        String s = "";
        String outputString = "";
        move = "";

        try {
            String curDir = System.getProperty("user.dir");

            String os = System.getProperty("os.name");
            ProcessBuilder processBuilder = null;

            // Check the os and load the appropriate chess engine
            
            if (os.contains("Windows")) {
                processBuilder = new ProcessBuilder(curDir + "/engine/Fruit-2-3-1.exe");
                processBuilder.directory(new File(curDir + "/engine/"));
            }
            else if(os.contains("Mac")) {
                processBuilder = new ProcessBuilder(curDir + "/engine/fruit231");
                processBuilder.directory(new File(curDir + "/engine/"));
            }
            else {
                processBuilder = new ProcessBuilder(curDir + "/engine/Fruit-2-3-1-Linux/Fruit-2-3-1-Linux");
                processBuilder.directory(new File(curDir + "/engine/Fruit-2-3-1-Linux/"));
            }

            p = processBuilder.start();
            stdInput = new BufferedReader(new InputStreamReader(p.getInputStream()));
            stdOutput = new BufferedWriter(new OutputStreamWriter(p.getOutputStream()));

        } catch (IOException ex) {
            ex.printStackTrace();
        }

        // wait for engine to boot up
        try {
            Thread.sleep(100);

            // tell engine to use uci interface
            tellEngine("uci");

            // give it a few milisecs
            Thread.sleep(100);

            // tell engine that the gui is ready
            tellEngine("isready");

            // give it a few milisecs
            Thread.sleep(20);

            // tell engine that we're starting a new game
            tellEngine("ucinewposition");

        } catch (Exception ex) {
            ex.printStackTrace();
        }

        engineReader = new Thread(new EngineReader(s));
        engineReader.start();

        return outputString;
    }

    public void stopEngine() {
        killEngineReader = true;
        tellEngine("quit");
        p.destroy();
    }

    public void waitForNextMove(int depth) {
        String depthString = String.valueOf(depth);
        tellEngine("go depth " + depthString);

        // TODO tell engine how much time is left on the clock
    }

    public void tellEngine(String inText) {
        try {
        stdOutput.write(inText + '\n');
        stdOutput.flush();
        } catch (IOException ex) {
        System.out.println("Failed writing to engine.");
        }    
    }

    private void setMove(String move) {
        this.move = move;
        board.getMove(move);
    }

    private String getMove() {
        return move;
    }

    public boolean getIsReady() {
        return isReady;
    }

    public void setIsReady(boolean choice) {
        isReady = choice;

        // if the engine isn't ready, tell it that we are
        if (!isReady) {
            tellEngine("isready");
        }
    }

    public class EngineReader implements Runnable {

        String s;
        String[] move;
        boolean alive = true;

        public EngineReader(String s) {
            this.s = s;
        }

        public void run() {
            while(!killEngineReader) {
                try {
                    Thread.sleep(20);
                    s = "";
                } catch (Exception ex) {ex.printStackTrace();}

                try {
                    s += stdInput.readLine();
                    engineTextArea.append(s + '\n');

                    // if engine tells us a move
                    if (s.contains("bestmove")) {
                        move = s.split(" ");
                        setMove(move[1]);
                        lastMoveLabel.setText(getMove());
                    }

                    // if engine is ready
                    if (s.contains("readyok")) {
                        setIsReady(true);
                    }
                } catch (Exception ex) {}
            }
        }
    }

    public class EngineListener implements Runnable {

        public void run() {
            while (true) {
                
                try {
                    Thread.sleep(50);
                } catch (InterruptedException ex) {
                    ex.printStackTrace();
                }

            }
        }
    }



    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JMenu engineMenu;
    private javax.swing.JTextArea engineTextArea;
    private javax.swing.JTextField inputField;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JMenuBar jMenuBar1;
    private javax.swing.JPanel jPanel1;
    private javax.swing.JPanel jPanel2;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JPopupMenu.Separator jSeparator1;
    private javax.swing.JLabel lastMoveLabel;
    private javax.swing.JButton sendButton;
    private javax.swing.JMenuItem startEngineMenuItem;
    private javax.swing.JMenuItem stopEngineMenuItem;
    // End of variables declaration//GEN-END:variables

}
